package cn.jw.starter.redis.core;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.TransportMode;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

import cn.hutool.core.util.StrUtil;
import cn.jw.starter.redis.core.api.JwRedisConfig;
import cn.jw.starter.redis.core.api.RedisApiService;
import cn.jw.starter.redis.core.api.RedisLockService;
import cn.jw.starter.redis.core.event.JwRedisEventListener;
import cn.jw.starter.redis.core.event.JwRedisPublishClient;

/**
 * redis自动配置类，负责创建redis和redission的bean
 *
 * @author wgslucky
 * @since 2024/4/30 17:39
 **/
@AutoConfiguration
@EnableConfigurationProperties(JwRedisConfig.class)
public class JwRedisAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(name = "stringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }

    @Bean
    public RedisApiService redisApiService(StringRedisTemplate stringRedisTemplate) {
        return new RedisApiService(stringRedisTemplate);
    }

    @Bean
    public RedissonClient redissonClient(RedisProperties redisProperties) {
        Config config = new Config();
        config.setTransportMode(TransportMode.NIO);

        if (StrUtil.isEmpty(redisProperties.getPassword())) {
            config.useSingleServer()
                .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
                .setDatabase(redisProperties.getDatabase());
        } else {
            config.useSingleServer()
                .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
                .setPassword(redisProperties.getPassword()).setDatabase(redisProperties.getDatabase());
        }
        return Redisson.create(config);
    }

    @Bean
    public MessageListenerAdapter messageListener(ApplicationContext context) {
        return new MessageListenerAdapter(new JwRedisEventListener(context));
    }

    @Bean
    public RedisMessageListenerContainer redisContainer(RedisConnectionFactory factory, ApplicationContext context) {
        final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        container.addMessageListener(messageListener(context),
            new ChannelTopic(JwRedisPublishClient.COMMON_REDIS_EVENT_CHANNEL));
        return container;
    }

    @Bean
    public JwRedisPublishClient redisPublishClient() {
        return new JwRedisPublishClient();
    }

    @Bean
    public RedisLockService redisLockService() {
        return new RedisLockService();
    }
}
